package com.robotic.udp;

import com.alibaba.fastjson2.JSONObject;
import com.robotic.common.utils.http.EnhancedHttpUtils;
import com.robotic.common.utils.http.HttpUtils;
import com.robotic.test.*;
import com.robotic.websocket.WebSocketServerKey;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import static com.robotic.tcp.RobotMonitor.robotX;
import static com.robotic.tcp.RobotMonitor.robotY;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;


@Component
@Slf4j
public class UnifiedUDPReceiver {

    @Autowired
    private WebSocketServerKey socketServerKey;

    // 监听端口号
    private static final int RECEIVE_PORT = 43897;
    // 缓冲区大小
    private static final int BUFFER_SIZE = 1024;
    // 假设协议使用小端序（Little-Endian）
    private static final ByteOrder BYTE_ORDER = ByteOrder.LITTLE_ENDIAN;

    // 指令码常量
    private static final int CMD_CHARGE_STATE = 0x91910250;
    private static final int CMD_MOTION_STATE = 0x1009;
    private static final int CMD_BATTERY_DATA = 0x21050F0A;
    private static final int CMD_CONTROLLER_SAFE = 0x100B;
    private static final int CMD_RCS_DATA = 0x1008;

    private volatile JSONObject lastLegOdom = new JSONObject(); // 缓存最新消息
    public static volatile JSONObject lastBattery = new JSONObject(); // 缓存最新消息
    public static volatile Integer lastRobotGaitState = null; // 缓存最新消息
    private volatile Float lastTotalMileageData = null; // 缓存最新消息
    private volatile Float lastCpuTemperature = null; // 缓存最新消息
    private volatile Float lastCpuFrequency = null; // 缓存最新消息
    private volatile Integer state = null; // 缓存最新消息

    // --- 新增的成员变量 ---
    // 用于记录"距离 > 5"这个条件开始满足的时间点。
    // 初始化为 null，表示计时器未启动。
    private Instant distanceCheckStartTime = null;

    // 将5分钟定义为一个常量，方便后续修改
    private static final Duration REQUIRED_DURATION = Duration.ofMinutes(1);

    private boolean isCall = false;

    static class CommandHead {
        final int code;
        final int parametersSize;
        final int type;

        CommandHead(byte[] headerBytes) {
            ByteBuffer buffer = ByteBuffer.wrap(headerBytes).order(ByteOrder.LITTLE_ENDIAN);
            this.code = buffer.getInt();
            this.parametersSize = buffer.getInt();
            this.type = buffer.getInt();
        }

        @Override
        public String toString() {
            return "CommandHead{" +
                    "code=0x" + Integer.toHexString(code) +
                    ", parametersSize=" + parametersSize +
                    ", type=" + type +
                    '}';
        }
    }

    @EventListener(ApplicationReadyEvent.class)
    public void r1() {
        int listenPort = 43897; // Example port, adjust as needed

        try (DatagramSocket socket = new DatagramSocket(listenPort)) {
            System.out.println("Listening for robot data on port " + listenPort);
            byte[] buffer = new byte[2048];

            while (true) {
                DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
                socket.receive(packet);

                byte[] receivedData = Arrays.copyOf(packet.getData(), packet.getLength());

                if (receivedData.length < 12) {
                    System.err.println("Received packet is too small to be a valid command.");
                    continue;
                }

                UnifiedUDPReceiver.CommandHead header = new UnifiedUDPReceiver.CommandHead(Arrays.copyOfRange(receivedData, 0, 12));
                byte[] data = Arrays.copyOfRange(receivedData, 12, receivedData.length);

                switch (header.code) {
                    case 0x91910250:
                        // Assuming the response value is in the 'parameters_size' field for simple commands
                        ChargeManagerState chargeState = new ChargeManagerState(header.parametersSize);
                        break;
                    case 0x1009:

                        MotionStateData motionState = new MotionStateData(data);
                        /*JSONObject jsonObject = new JSONObject();
                        jsonObject.put("X", motionState.getLegOdomPos()[0]);
                        jsonObject.put("Y", motionState.getLegOdomPos()[1]);
                        jsonObject.put("Z", motionState.getLegOdomPos()[2]);

                        // x y z轴的速度，m/s
                        JSONObject speed = new JSONObject();
                        speed.put("X", motionState.getLegOdomVel()[0]);
                        speed.put("Y", motionState.getLegOdomVel()[1]);
                        speed.put("Z", motionState.getLegOdomVel()[2]);
                        speed.put("max_forward_vel", motionState.getMaxForwardVel());
                        jsonObject.put("Speed", speed);*/
                        lastRobotGaitState = motionState.getBasicState();
                        //lastLegOdom = jsonObject;
                        break;
                    case 0x21050F0A:
                        BatterySensorData batteryData = new BatterySensorData(data);
                        lastBattery.put("voltageData", batteryData.getVoltage());
                        lastBattery.put("currentData", batteryData.getCurrent());
                        lastBattery.put("batteryData", batteryData.getBatteryLevel());
                        break;
                    case 0x100B:
                        ControllerSafeData safeData = new ControllerSafeData(data);
                        lastCpuTemperature = safeData.getCpuTemperature();
                        lastCpuFrequency = safeData.getCpuFrequency();
                        break;
                    case 0x1008:
                        RcsData rcsData = new RcsData(data);
                        lastTotalMileageData = Float.valueOf(rcsData.getTotalMileage()) / 100;
                        break;
                    case 0x11050F08:
                        ChargeManagerState chargeState1 = new ChargeManagerState(header.parametersSize);
                        double startX = Double.parseDouble("-0.37778768");
                        double startY = Double.parseDouble("0.099835418");
                        double distance = Math.sqrt(Math.pow(robotX - startX, 2) + Math.pow(robotY - startY, 2));
                        if (distance > 5) {
                            if (lastRobotGaitState != 4) {
                                // 条件满足：距离大于5米
                                if (distanceCheckStartTime == null) {
                                    // 如果计时器还未启动，这是条件第一次被满足的时刻。
                                    // 记录当前时间，启动计时器。
                                    distanceCheckStartTime = Instant.now();
                                } else {
                                    // 如果计时器已经启动，就检查从启动到现在经过了多长时间。
                                    Duration elapsed = Duration.between(distanceCheckStartTime, Instant.now());

                                    // a.compareTo(b) > 0 表示 a > b
                                    if (elapsed.compareTo(REQUIRED_DURATION) >= 0 && !isCall) {
                                        // 持续时间已经达到或超过5分钟，执行状态变更。
                                        this.state = 1;

                                        log.info("------------------拨打ip电话报警");
                                        Map<String, String> params = new HashMap<>();
                                        params.put("menuId", "2");
                                        params.put("extId", "8110");
                                        String response = EnhancedHttpUtils.sendPost("http://192.168.201.170:8070/api/phone/voiceCall", params);
                                        log.info("response = {}", response);
                                        isCall = true;
                                    }
                                }
                            } else {
                                state = chargeState1.getState();
                                distanceCheckStartTime = null;
                                isCall = false;
                            }
                        } else {
                            // 条件不满足：距离小于或等于5米
                            // 只要条件不满足，就必须重置计时器，这样才能保证“持续”的要求。
                            if (distanceCheckStartTime != null) {
                                distanceCheckStartTime = null;
                            }
                            state = chargeState1.getState();
                            isCall = false;
                        }

                        break;
                    default:
                        //System.out.println("Received unhandled command code: 0x" + Integer.toHexString(header.code));
                        break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    @Scheduled(fixedRate = 1000)
    public void runEverySecond() {
        // 电流，电压，电量
        if (!lastBattery.isEmpty()) {
            socketServerKey.sendOneMessage("battery", lastBattery.toString());
        }

        // 站立状态，总里程，CPU主频，CPU温度
        JSONObject status = new JSONObject();
        if (lastRobotGaitState != null) {
            status.put("robotGaitState", lastRobotGaitState);
        }
        if (lastTotalMileageData != null) {
            status.put("totalMileageData", lastTotalMileageData);
        }
        if (lastCpuFrequency != null) {
            status.put("cpuFrequency", lastCpuFrequency);
        }
        if (lastCpuTemperature != null) {
            status.put("cpuTemperature", lastCpuTemperature);
        }
        if (state != null) {
            status.put("state", state);
        }
        if (!status.isEmpty()) {
            socketServerKey.sendOneMessage("status", status.toString());
        }
    }
}
